home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
net
/
sun4.md
/
netIERecv.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-18
|
10KB
|
346 lines
/* netIERecv.c -
*
* Routines to manage the receive unit of the Intel ethernet chip.
*
* Copyright 1985, 1988 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/net/sun4.md/netIERecv.c,v 9.2 90/10/19 15:47:24 jhh Exp $ SPRITE (Berkeley)";
#endif
#include <sprite.h>
#include <netIEInt.h>
#include <sys.h>
#include <list.h>
/*
*----------------------------------------------------------------------
*
* NetIERecvUnitInit --
*
* Initialize the receive buffer lists for the receive unit and start
* it going.
*
* NOTE: One more buffer descriptor is allocated than frame descriptor
* because Sun claims that this gets rid of a microcode bug.
*
* Results:
* None.
*
* Side effects:
* The receive frame descriptor and buffer lists are initialized.
*
*----------------------------------------------------------------------
*/
void
NetIERecvUnitInit(statePtr)
NetIEState *statePtr;
{
int i;
register volatile NetIERecvBufDesc *recvBufDescPtr;
register volatile NetIERecvFrameDesc *recvFrDescPtr;
register volatile NetIESCB *scbPtr;
int bufferSize;
bufferSize = NET_IE_RECV_BUFFER_SIZE - sizeof(Net_EtherHdr);
/*
* Allocate the receive buffer descriptors.
*/
for (i = 0; i < NET_IE_NUM_RECV_BUFFERS; i++) {
recvBufDescPtr = (volatile NetIERecvBufDesc *) NetIEMemAlloc(statePtr);
if (recvBufDescPtr == (volatile NetIERecvBufDesc *) NIL) {
panic("No memory for a receive buffer descriptor pointer\n");
}
*(short *)recvBufDescPtr = 0; /* Clear out the status word */
if (i == 0) {
statePtr->recvBufDscHeadPtr = recvBufDescPtr;
statePtr->recvBufDscTailPtr = recvBufDescPtr;
} else {
statePtr->recvBufDscTailPtr->nextRBD =
NetIEOffsetFromSUNAddr((int) recvBufDescPtr,
statePtr);
statePtr->recvBufDscTailPtr->realNextRBD = recvBufDescPtr;
statePtr->recvBufDscTailPtr = recvBufDescPtr;
}
/*
* Point the header to its buffer. It is pointed to the buffer plus
* the size of the ethernet header so that when we receive the
* packet we can fill in the ethernet header.
*/
recvBufDescPtr->bufAddr =
NetIEAddrFromSUNAddr((int) (statePtr->netIERecvBuffers[i] +
sizeof(Net_EtherHdr)));
recvBufDescPtr->realBufAddr = statePtr->netIERecvBuffers[i];
NetBfShortSet(recvBufDescPtr->bits2, BufSizeHigh, bufferSize >> 8);
NetBfShortSet(recvBufDescPtr->bits2, BufSizeLow, bufferSize & 0xff);
NetBfShortSet(recvBufDescPtr->bits2, RBDEndOfList, 0);
}
/*
* Link the last element to the first to make it circular and mark the last
* element as the end of the list.
*/
recvBufDescPtr->nextRBD =
NetIEOffsetFromSUNAddr((int) statePtr->recvBufDscHeadPtr,
statePtr);
recvBufDescPtr->realNextRBD = statePtr->recvBufDscHeadPtr;
NetBfShortSet(recvBufDescPtr->bits2, RBDEndOfList, 1);
/*
* Now allocate the receive frame headers.
*/
for (i = 0; i < NET_IE_NUM_RECV_BUFFERS - 1; i++) {
recvFrDescPtr = (volatile NetIERecvFrameDesc *) NetIEMemAlloc(statePtr);
if (recvFrDescPtr == (volatile NetIERecvFrameDesc *) NIL) {
panic("No memory for a receive frame descriptor pointer\n");
}
*(short *)recvFrDescPtr = 0; /* Clear out the status word */
NetBfWordSet(recvFrDescPtr->bits, EndOfList, 0);
NetBfWordSet(recvFrDescPtr->bits, Suspend, 0);
if (i == 0) {
statePtr->recvFrDscHeadPtr = recvFrDescPtr;
statePtr->recvFrDscTailPtr = recvFrDescPtr;
/*
* The first receive frame descriptor points to the list of buffer
* descriptors.
*/
recvFrDescPtr->recvBufferDesc =
NetIEOffsetFromSUNAddr((int) statePtr->recvBufDscHeadPtr,
statePtr);
} else {
recvFrDescPtr->recvBufferDesc = NET_IE_NULL_RECV_BUFF_DESC;
statePtr->recvFrDscTailPtr->nextRFD =
NetIEOffsetFromSUNAddr((int) recvFrDescPtr,
statePtr);
statePtr->recvFrDscTailPtr->realNextRFD = recvFrDescPtr;
statePtr->recvFrDscTailPtr = recvFrDescPtr;
}
}
/*
* Link the last element to the first to make it circular.
*/
recvFrDescPtr->nextRFD =
NetIEOffsetFromSUNAddr((int) statePtr->recvFrDscHeadPtr,
statePtr);
recvFrDescPtr->realNextRFD = statePtr->recvFrDscHeadPtr;
NetBfWordSet(recvFrDescPtr->bits, EndOfList, 1);
scbPtr = statePtr->scbPtr;
/*
* Now start up the receive unit. To do this we first make sure that
* it is idle. Then we start it up.
*/
if (!NetBfShortTest(scbPtr->statusWord, RecvUnitStatus, NET_IE_RUS_IDLE)) {
printf("Intel: The receive unit is not idle!!!\n");
NetBfShortSet(scbPtr->cmdWord, RecvUnitCmd, NET_IE_RUC_ABORT);
NET_IE_CHANNEL_ATTENTION(statePtr);
NetIECheckSCBCmdAccept(scbPtr);
}
scbPtr->recvFrameAreaOffset =
NetIEOffsetFromSUNAddr((int) statePtr->recvFrDscHeadPtr,
statePtr);
NetBfShortSet(scbPtr->cmdWord, RecvUnitCmd, NET_IE_RUC_START);
NET_IE_CHANNEL_ATTENTION(statePtr);
NetIECheckSCBCmdAccept(scbPtr);
NET_IE_DELAY(NetBfShortTest(scbPtr->statusWord, RecvUnitStatus,
NET_IE_RUS_READY));
if (!NetBfShortTest(scbPtr->statusWord, RecvUnitStatus, NET_IE_RUS_READY)){
printf("Intel: Receive unit never became ready.\n");
}
return;
}
/*
*----------------------------------------------------------------------
*
* NetIERecvProcess --
*
* Process a newly received packet.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
NetIERecvProcess(dropPackets, statePtr)
Boolean dropPackets; /* Drop all packets. */
NetIEState *statePtr;
{
register volatile NetIERecvBufDesc *recvBufDescPtr;
register volatile NetIERecvFrameDesc *recvFrDescPtr;
register volatile Net_EtherHdr *etherHdrPtr;
volatile NetIERecvFrameDesc *newRecvFrDescPtr;
int size;
int num;
recvFrDescPtr = statePtr->recvFrDscHeadPtr;
/*
* If not initialized then forget the interrupt.
*/
if (recvFrDescPtr == (NetIERecvFrameDesc *) NIL) {
return;
}
/*
* Loop as long as there are packets to process.
*/
while (NetBfWordTest(recvFrDescPtr->bits, Done, 1)) {
statePtr->stats.packetsRecvd++;
/*
* If this packet has a buffer associated with it then process it.
*/
if ((unsigned short) recvFrDescPtr->recvBufferDesc !=
NET_IE_NULL_RECV_BUFF_DESC) {
recvBufDescPtr = statePtr->recvBufDscHeadPtr;
size = NetBfShortGet(recvBufDescPtr->bits1, CountLow) +
(NetBfShortGet(recvBufDescPtr->bits1, CountHigh) << 8) +
sizeof(Net_EtherHdr);
/*
* Put the ethernet header into the packet.
*/
etherHdrPtr = (Net_EtherHdr *) recvBufDescPtr->realBufAddr;
etherHdrPtr->source = recvFrDescPtr->srcAddr;
etherHdrPtr->destination = recvFrDescPtr->destAddr;
etherHdrPtr->type = recvFrDescPtr->type;
/*
* Call higher level protocol to process the packet.
*/
if (!dropPackets) {
Net_Input(statePtr->interPtr, (Address)etherHdrPtr, size);
}
/*
* Make the element that was just processed the last element in the
* list. Since this is circular list, no relinking has to be done.
*/
*(short *) recvBufDescPtr = 0; /* Clear out the status word. */
NetBfShortSet(recvBufDescPtr->bits2, RBDEndOfList, 1);
NetBfShortSet(statePtr->recvBufDscTailPtr->bits2, RBDEndOfList, 0);
statePtr->recvBufDscTailPtr = recvBufDescPtr;
statePtr->recvBufDscHeadPtr = recvBufDescPtr->realNextRBD;
}
/*
* Make the element that was just processed the last element in the
* list. Since this is circular list, no relinking has to be done.
*/
newRecvFrDescPtr = recvFrDescPtr->realNextRFD;
recvFrDescPtr->recvBufferDesc = NET_IE_NULL_RECV_BUFF_DESC;
NetBfWordSet(recvFrDescPtr->bits, EndOfList, 1);
*(short *) recvFrDescPtr = 0;
NetBfWordSet(statePtr->recvFrDscTailPtr->bits, EndOfList, 0);
statePtr->recvFrDscTailPtr = recvFrDescPtr;
statePtr->recvFrDscHeadPtr = newRecvFrDescPtr;
recvFrDescPtr = newRecvFrDescPtr;
}
/*
* Record statistics about packets.
*/
if (statePtr->scbPtr->crcErrors != 0) {
num = statePtr->scbPtr->crcErrors;
statePtr->scbPtr->crcErrors = 0;
statePtr->stats.crcErrors += NetIEShortSwap(num);
}
if (statePtr->scbPtr->alignErrors != 0) {
num = statePtr->scbPtr->alignErrors;
statePtr->scbPtr->alignErrors = 0;
statePtr->stats.frameErrors += NetIEShortSwap(num);
}
if (statePtr->scbPtr->resourceErrors != 0) {
num = statePtr->scbPtr->resourceErrors;
statePtr->scbPtr->resourceErrors = 0;
statePtr->stats.recvPacketsDropped += NetIEShortSwap(num);
}
if (statePtr->scbPtr->overrunErrors != 0) {
num = statePtr->scbPtr->overrunErrors;
statePtr->scbPtr->overrunErrors = 0;
statePtr->stats.overrunErrors += NetIEShortSwap(num);
}
/*
* See if the receive unit is ready. If it is, then return.
*/
if (NetBfShortTest(statePtr->scbPtr->statusWord, RecvUnitStatus,
NET_IE_RUS_READY)) {
return;
}
/*
* Otherwise reinitialize the receive unit. To do this set the head
* receive frame pointer to point to the head of the list of buffer
* headers and give the reinit command to the chip.
*/
printf("Reinit recv unit\n");
statePtr->recvFrDscHeadPtr->recvBufferDesc =
NetIEOffsetFromSUNAddr((int) statePtr->recvBufDscHeadPtr,
statePtr);
statePtr->scbPtr->recvFrameAreaOffset =
NetIEOffsetFromSUNAddr((int) statePtr->recvFrDscHeadPtr,
statePtr);
NET_IE_CHECK_SCB_CMD_ACCEPT(statePtr->scbPtr);
NetBfShortSet(statePtr->scbPtr->cmdWord, RecvUnitCmd, NET_IE_RUC_START);
NET_IE_CHANNEL_ATTENTION(statePtr);
return;
}